
var map;
var defaultCenter = new GLatLng(42.374969, -71.116261);
var allBldgs = {};
var allRooms = {};
var markers = {};
var markerIcons = {};

var visBldgs = {};
var visRooms = {};

var selectedRoom;
var selectedBldg;

var console, resultsPanel, searchPanel, inputSeats, inputProjector, inputComputer, inputKeywords, inputBounds, summary;

var loadedBldgs = false;
var loadedRooms = false;

function allLoaded()
{
	return loadedBldgs && loadedRooms; 
}

var filters = {
	seats:0,
	projector:false,
	computer:false,
	bounds:true
};

function initialize() {
	initializeElementNames();
	
	var filterDigits = function () { 
	    if (this.value.match(/[^0-9]/g)) {
	      this.value = this.value.replace(/[^0-9]/g,'');
	    }
  };
	
	//jQuery('.digitsOnly').change(filterDigits);
	$('.digitsOnly').keyup(filterDigits);
	
	makeMarkerColors();
	makeColorKey();
	
	var countP = document.createElement("div");
	countP.id = "countP";
	countP.className = "clearfix"; 
	//summary.appendChild(countP);
	
	var ce = document.createElement("div");
	ce.id = "collapseExpand";
	ce.innerHTML = '<a href="javascript:expandAll()" title="Expand all buildings">expand all</a><br/><a href="javascript:collapseAll()" title="Collapse all buildings">collapse all</a>';
	summary.appendChild(ce);
	summary.appendChild(countP);
	
	if(!$.cookie("closeHelp"))
	{
	  $("#helpPanel").removeClass("hidden");
	}
	
	w("Initializing...");
	initializeMap();
	loadAll();
	
	waitFor(allLoaded,
			function() {	
		makeAllMarkers();
		makeBldgDivs();
		makeRoomDivs();
		
		for(bldgid in allBldgs)
		{
			visBldgs[bldgid] = allBldgs[bldgid];
		}
		
		for(roomid in allRooms)
		{
			visRooms[roomid] = allRooms[roomid];
		}

		updateFilters();
		
	});
	
}

function initializeMap() {
	if (GBrowserIsCompatible()) {
		map = new GMap2(document.getElementById("mapCanvas"), {
			size : new GSize(640, 640)
		});
		map.setCenter(defaultCenter, 14);
		map.addControl(new GLargeMapControl3D());

		var mapControl = new GMapTypeControl();
		map.addControl(mapControl);
		
		map.addMapType(G_PHYSICAL_MAP);
		
		map.enableScrollWheelZoom();
		G_NORMAL_MAP.getMinimumResolution = G_SATELLITE_MAP.getMinimumResolution = 
			G_HYBRID_MAP.getMinimumResolution = G_PHYSICAL_MAP.getMinimumResolution = function(){return 14;};
		
		GEvent.addListener(map, "moveend", function() {w("Map moved"); updateFilters(); });
		
	}
}

function initializeElementNames() {
	resultsPanel = document.getElementById('resultsPanel');
	console = document.getElementById('console');
	searchPanel = document.getElementById('searchPanel');
	inputSeats = document.getElementById('inputSeats');
	inputComputer = document.getElementById('inputComputer');
	inputProjector = document.getElementById('inputProjector');
	inputKeywords = document.getElementById('inputKeywords');
	inputBounds = document.getElementById('inputBounds');
	summary = document.getElementById('summary');
}

function loadAll() {
	$.getJSON('data/good-bldgs.json', function(data) {
		var numBldgs = Object.size(data);
		var arr = Array();

		for (i = 0; i < numBldgs; ++i) {
			var bldgid = String('i' + data[i].bldgid);
			var bldg = new Bldg(bldgid);
			bldg.name = data[i].name;
			bldg.lat = Number(data[i].lat);
			bldg.lng = Number(data[i].lng);
			arr.push(bldg);
		}

		arr.sort(function(o1, o2) {
			return compare(o1.name, o2.name);
		});

		for (i = 0; i < arr.length; ++i) {
			var bldg = arr[i];
			allBldgs[bldg.bldgid] = bldg;
		}
		
		loadedBldgs = true;


		
	});

	$.getJSON('data/rooms.json', function(data) {
		var numRooms = Object.size(data);
		var arr = Array();
		for (i = 0; i < numRooms; ++i) {
			var room = new Room('i' + String(data[i].id)); 

			if(!("bldgid" in data[i]) || data[i].bldgid == "") {
				continue;
			}

			room.bldgid = 'i' + data[i].bldgid;
			room.seats = Number(data[i].seats);
			room.computer = strToBool(data[i].computer);
			room.projector = strToBool(data[i].projector);
			room.photo = data[i].photo;
			room.name = data[i].room;
			room.type = data[i].type;
			room.examseats = data[i].examseats;
			room.leftseats = data[i].leftseats;
			
			arr.push(room);
		}

		arr.sort(function(o1, o2) {
			return compare(o1.name, o2.name);
		});

		w("Room array has length " + arr.length);

		for (i = 0; i < arr.length; ++i) {
			var room = arr[i];
			allRooms[room.roomid] = room;
		}

		w("Loaded " + Object.size(allRooms) + " rooms");
		
		loadedRooms = true;
		

	});

}

function makeAllMarkers()
{
	var len = Object.size(allBldgs);
	for (bldgid in allBldgs)
	{
		var bldg = allBldgs[bldgid];
		var point = new GLatLng(bldg.lat, bldg.lng);
		var marker = new GMarker(point, {title:bldg.name, hide:true});
		GEvent.addListener(marker, "click", f_clickedMarker(bldg));
		markers[String(bldg.bldgid)] = marker;
		map.addOverlay(marker);
	}
	w("Created " + len + " markers");
}


function makeBldgDivs() {
	for (bldgid in allBldgs) {
		var bldg = allBldgs[bldgid];
		
		var div = document.createElement('div');
		div.className = 'bldg unexpanded';
		div.id = 'container_' + bldgid;
		div.innerHTML = '<a class="bldglink" title="View map in new window (to get directions, etc.)" target="_blank" href="http://maps.google.com/?q=' + bldg.lat + ',' + bldg.lng + ' (' + bldg.name + ')">map</a>' +
		                '<div class="bldgheader"><span class="bldgname">' + bldg.name + '</span>' +
		                '<span class="count" title="Number of rooms (matching/total)" id="count_' + bldgid + '"></span></div>';
		resultsPanel.appendChild(div);

		var header = $('#container_' + bldgid + ' .bldgheader');
		header.click(f_toggleBldg(bldgid));
		
		var roomsDiv = document.createElement('div');
		roomsDiv.className = 'rooms';
		roomsDiv.id = 'rooms_' + bldgid;
		div.appendChild(roomsDiv);
	}
}

function makeRoomDivs() {
	// w("Entered makeRoomDivs()");
	for (roomid in allRooms)
	{
		var room = allRooms[roomid];
		var bldgRoomsDiv = document.getElementById("rooms_" + room.bldgid);
		bldgRoomsDiv.appendChild(getRoomDiv(roomid));
		// w("Added room " + roomid + " to " + room.bldgid);
		
		$('#roomName_' + roomid).click(f_selectRoomid(roomid));
	}
}


function getRoomDiv(id)
{
	var room = allRooms[id];
	var div = document.createElement('div');
	div.className = "room";
	div.id = "room_" + id;
	div.innerHTML = '<p class="roomName" id="roomName_' + id + '">' + room.name + '<span class="seatCount">' + room.seats + ' seats</span></p> <div class="roomInfo" id="roomInfo_' + id +  '"></div>'; 
	return div;
}


/**
 * Write to the console
 */
function w(text) {
	var elem = document.createElement('p');
	elem.innerHTML = text;
	console.appendChild(elem);
	console.scrollTop = console.scrollHeight;
}

s = JSON.stringify; 

/**
 * Get the size of an associative array
 * 
 * @param obj
 * @return
 */
Object.size = function(obj) {
	var size = 0, key;
	for (key in obj) {
		if (obj.hasOwnProperty(key))
			size++;
	}
	return size;
};



/**
 * Generic comparison function
 * 
 * @param s1
 * @param s2
 * @return
 */
function compare(s1, s2) {
	if (s1 < s2) {
		return -1;
	} else if (s1 > s2) {
		return 1;
	} else {
		return 0;
	}
}

function strToBool(str)
{
	str = str.toLowerCase();
	if (str == "yes" || str == "true" || str == "y")
	{
		return true;
	}
	return false;
}


/**
 * Waits for 'condition' to be true, and then calls 'handler'
 * 
 * @param condition
 * @param handler
 * @param timeout
 * @return
 */
function waitFor(condition, handler, timeout) {
	// w("Entered waitFor");
	if(!timeout) {
		var timeout = 50;
	}
	
	if (condition())
	{
		w("Stopped waiting.");
		handler();
	}
	else {
		setTimeout(function() { waitFor(condition, handler, timeout); }, timeout);
	}
}


/**
 * Returns a closure for clickedMarker. This is needed because JS has a problem
 * with declaring functions inside loops.
 * 
 * @param bldg
 * @return
 */
function f_clickedMarker(bldg)
{
	return function() { clickedMarker(bldg); };
}

function clickedMarker(bldg) {
	w("Clicked marker for " + bldg.name);
	expandBldgid(bldg.bldgid);
	selectBldg(bldg);
	scrollToBldgid(bldg.bldgid);
}



function updateFilters()
{
	setTimeout(function()
	{
		w("Entered updateFilters()");
		// w("inputSeats " + inputSeats.value);
		filters.seats = inputSeats.value ? inputSeats.value : 0;
		filters.projector = (inputProjector.checked) ? true : false;
		filters.computer = (inputComputer.checked) ? true : false;
		filters.useBounds = (inputBounds.checked) ? true : false;
		filters.keywords = inputKeywords.value;
		w(JSON.stringify(filters));
		
		filterRooms();
		filterBldgs();
		updateDisplay();
		w("Exited updateFilters()");
	}
	, 10);

}

function updateDisplay()
{
	w("updateDisplay");
	var minMaxRooms = getMinMaxRooms();
	
	updateColorKey(minMaxRooms.min, minMaxRooms.max);
	var numRooms = Object.size(visRooms);
	var numBldgs = Object.size(visBldgs);
	document.getElementById("countP").innerHTML = "Showing <strong>" + numRooms + "</strong> room" + (numRooms == 1 ? "" : "s") + " in <strong>" + numBldgs + "</strong> building" + (numBldgs == 1 ? "" : "s") + ".";
	
	$("#resultsPanel .bldg.first").removeClass("first");
	$("#resultsPanel .bldg.last").removeClass("last");
	
	for (bldgid in allBldgs)
	{
		var bldg = allBldgs[bldgid];
		var container = $("#container_" + bldgid);
		var marker = markers[bldgid];
		
		if (bldgid in visBldgs) {
		  
      var numAllRooms = Object.size(bldg.getAllRooms());
      var numVisRooms = Object.size(bldg.getVisRooms());
      var countString = "(" + numVisRooms + "/" + numAllRooms + ")";

			var color = getColor(numVisRooms, minMaxRooms.min, minMaxRooms.max);
			setMarkerIcon(bldgid, color, numVisRooms, (bldg == selectedBldg));
			
			container.removeClass("hidden");  
			marker.show();
			

			
			var countSpan = document.getElementById("count_" + bldgid);
			countSpan.innerHTML = countString;
			
		}
		else {
			container.addClass("hidden");
			marker.hide();
		}
		
	}
	
	$("#resultsPanel .bldg:visible:first").addClass("first");
	$("#resultsPanel .bldg:visible:last").addClass("last");
	
	for (roomid in allRooms)
	{
		var room = allRooms[roomid];
		var roomDiv = $("#room_" + roomid);
		if (roomid in visRooms) {
			roomDiv.removeClass("hidden");
		}
		else {
			roomDiv.addClass("hidden");
		}
	}
}

function makeColorKey()
{
  var outer = document.createElement("div");
  outer.id = "colorScale";
  outer.className = "clearfix";
  outer.title = "Color scale - number of matching rooms in a building. \nThe limits automatically adjust depending on search results.";
  summary.appendChild(outer);
  
  for (i = 0; i < numSteps; ++i)
  {
    var div = document.createElement("div");
    div.className = "scaleValue";
    
    if (i == 0)
    {
      div.className += " first";
      div.style.color = "#" + colors[numSteps-1].toHex();
    }
    if (i == numSteps - 1)
    {
      div.className += " last";
      div.style.color = "#" + colors[0].toHex();
    }
    
    div.id = "scaleValue_" + i;
    div.style.backgroundColor = "#" + colors[i].toHex();
    div.style.width = Math.floor((outer.offsetWidth -(numSteps + 1)*5) / (numSteps + 1)) + "px";
    outer.appendChild(div);
  }
  
  document.getElementById("scaleValue_0").style.color = "#" + colors[numSteps-1].toHex();
  document.getElementById("scaleValue_" + (numSteps-1)).style.color = "#" + colors[0].toHex();
}

function updateColorKey(min, max)
{
  var first = document.getElementById("scaleValue_0");
  first.innerHTML = min;
  
  var last = document.getElementById("scaleValue_" + String(numSteps-1));
  last.innerHTML = max;
}

function getMinMaxRooms()
{
  var min = Infinity;
  var max = 0;
  for (bldgid in visBldgs)
  {
    var bldg = visBldgs[bldgid];
    var numVisRooms = Object.size(bldg.getVisRooms()); 
    if(numVisRooms > max)
    {
      max = numVisRooms;
    }
    if (numVisRooms < min)
    {
      min = numVisRooms;
    }
  }
  return {"max":max, "min":min};
}

function collapseBldgid(bldgid)
{
	w("Collapsing " + bldgid);
	var container = $("#container_" + bldgid);
	container.addClass("unexpanded");
}

function expandBldgid(bldgid)
{
	w("Expanding " + bldgid);
	var container = $("#container_" + bldgid);
	container.removeClass("unexpanded");
}

function toggleBldg(bldgid)
{
	var container = $('#container_' + bldgid);
	
	// Expand and select
	if (container.hasClass('unexpanded'))
	{
		selectBldgid(bldgid);
		expandBldgid(bldgid);
		$("#resultsPanel .bldg.selected .room:visible:first").addClass("first");
		if(!filters.useBounds)
		{
		  map.panTo(markers[bldgid].getLatLng());
		}
	}
	else
	{
		collapseBldgid(bldgid);
	}
}

function f_toggleBldg(bldgid)
{
	return (function() { toggleBldg(bldgid); });
}

function selectBldgid(bldgid)
{
	var bldg = null;
	try
	{
		bldg = allBldgs[bldgid];
	}
	finally {}
	
	selectBldg(bldg);
}

function selectBldg(bldg)
{
	if (bldg && selectedBldg != bldg)
	{
		var newContainer = $('#container_' + bldg.bldgid);
		newContainer.addClass('selected');
		setMarkerIconSelected(bldg.bldgid, true);

		unselectBldg(selectedBldg);
		w("Selected " + bldg.bldgid + " (" + bldg.name + ")");
	}
	else if (!bldg)
	{
		unselectBldg(selectedBldg);
	}

	$("#resultsPanel .bldg.selected .room:visible:first").addClass("first");
	
	// Update selectedBldg regardless of whether bldg is null
	selectedBldg = bldg;
	
	if (selectedRoom && selectedRoom.getBldg() != bldg)
	{
		unselectRoom(selectedRoom);
	}
	
//	var myVisRooms = bldg.getVisRooms();
//	if(Object.size(myVisRooms) == 1)
//	{
//	  for (roomid in myVisRooms)
//	  {
//	    selectRoomid(roomid);
//	  }
//	}
	
}

function unselectBldg(bldg)
{
	if (!bldg) return;
	var selContainer = $('#container_' + bldg.bldgid);
	$("#resultsPanel .bldg.selected .room.first").removeClass("first");
	selContainer.removeClass('selected');
	setMarkerIconSelected(bldg.bldgid, false);
}


function selectRoomid(roomid)
{
	var room = allRooms[roomid];
	w('Selected room ' + room.roomid + ' (' + room.name + ')');
	
	if (room != selectedRoom)
	{
		unselectRoom(selectedRoom);
		selectedRoom = room;
	}
	makeRoomInfoDiv(roomid);
	var selRoomDiv = $('#room_' + room.roomid);
	selRoomDiv.addClass('selected');
	
	selectBldg(room.getBldg());
	
  if(!filters.useBounds)
  {
    map.panTo(markers[room.bldgid].getLatLng());
  }
}

function f_selectRoomid(roomid)
{
	return function() { selectRoomid(roomid); };
}

function unselectRoom(room)
{
	if (!room) return;
	var selRoomDiv = $('#room_' + room.roomid);
	selRoomDiv.removeClass('selected');
	
	if (selectedRoom == room)
	{
		selectedRoom = null;
	}
}


function filterRooms()
{
	visRooms = {};
	var bounds = map.getBounds();
	
	for (roomid in allRooms)
	{
		var room = allRooms[roomid];
		var matches = 
			matchesPeople(room, filters.seats) &&
			matchesProjector(room, filters.projector) &&
			matchesComputer(room, filters.computer) &&
			(!filters.useBounds || matchesBounds(room, bounds)) &&
			matchesKeywords(room, filters.keywords);
		
		if(matches) {
			visRooms[roomid] = room;
		}
	}
	w(Object.size(visRooms) + " rooms visible");
}

function filterBldgs()
{
	visBldgs = {};
	for(roomid in visRooms)
	{
		var room = visRooms[roomid];
		visBldgs[room.bldgid] = allBldgs[room.bldgid];
	}
	w(Object.size(visBldgs) + " bldgs visible");
}



function scrollToBldgid(bldgid)
{
	var div = document.getElementById("container_" + bldgid);
	
	resultsPanel.scrollTop = div.offsetTop - resultsPanel.offsetTop - 10;
}

function makeRoomInfoDiv(roomid)
{
	var room = allRooms[roomid];
	var div = document.getElementById('roomInfo_' + roomid);
	if (div.innerHTML != "") return;
	
	if (room.photo)
	{
		div.innerHTML += '<a href="' + room.photo + '" target="roomPhoto" title="View full image"><img class="roomPhoto" src="' + room.photo + '"/></a>';
	}
	
	div.innerHTML += '<p>' + room.type + '</p>' +
		'<p><span class="infoCaption"> Seats:</span> ' + room.seats + '</p>' +
	'<p><span class="infoCaption"> Projector:</span> ' + boolToYesNo(room.projector) + '</p>' +
	'<p><span class="infoCaption"> Computer:</span> ' + boolToYesNo(room.computer) + '</p>';
	
	if (room.examseats)
	{
	  div.innerHTML += '<p><span class="infoCaption"> Exam seats:</span> ' + room.examseats + '</p>';
	}
	
	 if (room.lefteats)
	  {
	    div.innerHTML += '<p><span class="infoCaption"> Left-handed seats:</span> ' + room.leftseats + '</p>';
	  }
	
	div.innerHTML += '<div style="clear:both;"/>';
}

function boolToYesNo(bool)
{
	return bool ? "Yes" : "No";
}

function toggleConsole()
{
  var c = $(console);
  c.toggleClass("hidden");
}

function expandAll()
{
  for (bldgid in visBldgs)
  {
    expandBldgid(bldgid);
  }
}

function collapseAll()
{
  for (bldgid in visBldgs)
  {
    collapseBldgid(bldgid);
  }
}

function closeHelp()
{
  $.cookie("closeHelp","true", {expires: 7});
  $("#helpPanel").addClass("hidden");
}

function showHelp()
{
  $("#helpPanel").toggleClass("hidden");
}
